import traceback
import re
import qtawesome as qta
from .matter_enum import *


def cmd_send_out(disp, ui, ssh_ch, chip_path, cmd: str) -> None:
    """
    chip-tool env config and control command process
    :param disp: queue object, inheriting the existing instance of the main thread
    :param ui: ui object, inheriting the existing instance of the main thread
    :param ssh_ch: ssh client object, inheriting the existing instance of the main thread
    :param cmd: matter commands
    :return: None
    """
    # >> 1. parameters init
    if not ssh_ch:
        disp.put((ui.keynote, 'QTextBrowser.append', 'SSH connection invalid'))
        return
    _path = chip_path
    _clu_id, _ep, _att_id, _att_name, _cmd_id, _cmd_name = None, None, None, None, None, None
    _node_id = ui.dut_node_id.currentText()
    _commissioner_name = re.findall('_(.*)', _node_id)
    # > cluster control parameters
    _tra, _opt, _ovr = ui.trans_time.currentText(), ui.option_mask.currentText(), ui.override.currentText()
    if not _tra.isdecimal() or not _opt.isdecimal() or not _ovr.isdecimal():
        _tra, _opt, _ovr = '0', '0', '0'
    # > for multi-fabric dut, if _c_name the command should be ended with '--commissioner-name {_c_name}'
    _dst, _c_name = _node_id, None
    if len(_commissioner_name) > 0:
        _dst = _node_id.replace(f'_{_commissioner_name[0]}', '')
        _c_name = _commissioner_name[0]

    # >> 2. cmd format
    _cmd = ''
    match cmd:
        case 'otbr_agent_state':
            _cmd = 'sudo service otbr-agent status'
        case 'otbr_web_state':
            _cmd = 'sudo service otbr-web status'
        case 'otbr_agent_restart':
            _cmd = 'sudo service otbr-agent restart'
        case 'otbr_mdns_state':
            _cmd = 'sudo service mdns status'
        case 'otbr_thread_start':
            _cmd = 'sudo ot-ctl thread start'
        case 'otbr_get_pskc':
            _cmd = 'sudo ot-ctl pskc'
        case 'otbr_rcp_reset':
            _cmd = 'sudo ot-ctl reset'
        case 'otbr_factory_reset':
            _cmd = 'sudo ot-ctl factoryreset'
        case 'otbr_dataset_active':
            _cmd = 'sudo ot-ctl dataset active -x'
        case 'otbr_show_extpanid':
            _cmd = 'sudo ot-ctl extpanid'
        case 'app_path_setting':
            """
            # TODO
            _path = ui.app_path.text()
            if r'/' not in _path:
                disp.put((ui.keynote, 'QTextBrowser.append',
                          'Default chip-tool app path is /home/ubuntu/apps/, '
                          'if you want to modify it please enter your absolute path'))
                return
            _vbox, _hbox = QVBoxLayout(), QHBoxLayout()
            _panel = QLabel()
            _conform, _cancle = QPushButton("Confirm"), QPushButton("Cancel")
            _panel.setText(f'Chip-tool app path will be set to: \n\t{path}\nPlease confirm it or cancel to default path')
            _hbox.addWidget(_conform)
            _vbox.addWidget(_panel)
            _vbox.addWidget(_cancle)
            _vbox.addLayout(_hbox)
            _conform.clicked.connect()
            chip_path = _path
            """
        case 'check_paa_path':
            _cmd = 'tree -L 2'
        case 'payload_parse':
            _payload = ui.payload.text()
            if _payload.isdecimal() and (len(_payload) == 11):
                _cmd = f'{chip_path}chip-tool payload parse-setup-payload "{_payload}"'
            elif 'MT:' in _payload:
                _cmd = f'{chip_path}chip-tool payload parse-setup-payload "{_payload}"'
            else:
                disp.put((ui.keynote, 'QTextBrowser.append', 'Invalid qrcode or manualPairingCode'))
        case 'basic-read':
            _att_name = ui.attrib_id_basic.currentText()
            _cmd = f'{chip_path}chip-tool basicinformation read {_att_name} {_dst} 0'
            if _att_name == '0xFFFFFFFF':
                _cmd = f'{chip_path}chip-tool basicinformation read-by-id 0xFFFFFFFF {_dst} 0'
        case 'descriptor_read':
            _att_name = ui.attrib_id_discriptor.currentText()
            _ep = ui.end_point.currentText()[-1]
            _cmd = f'{chip_path}chip-tool descriptor read {_att_name} {_dst} {_ep}'
            if _att_name == '0xFFFFFFFF':
                _cmd = f'{chip_path}chip-tool descriptor read-by-id 0xFFFFFFFF {_dst} {_ep}'
        case 'read_general_commissioning':
            _att_name = ui.attrib_id_general_commissioning.currentText()
            _cmd = f'{chip_path}chip-tool generalcommissioning read {_att_name} {_dst} 0'
            if _att_name == '0xFFFFFFFF':
                _cmd = f'{chip_path}chip-tool generalcommissioning read-by-id 0xFFFFFFFF {_dst} 0'
        case 'read_noc':
            _att_name = ui.attrib_noc.currentText()
            _cmd = f'{chip_path}chip-tool operationalcredentials read {_att_name} {_dst} 0'
            if _att_name == '0xFFFFFFFF':
                _cmd = f'{chip_path}chip-tool operationalcredentials read-by-id 0xFFFFFFFF {_dst} 0'
        case 'read_nc':
            _att_name = ui.attrib_nc.currentText()
            _cmd = f'{chip_path}chip-tool networkcommissioning read {_att_name} {_dst} 0'
            if _att_name == '0xFFFFFFFF':
                _cmd = f'{chip_path}chip-tool networkcommissioning read-by-id 0xFFFFFFFF {_dst} 0'
        case 'read_cadmin':
            _att_name = ui.attrib_cadmin.currentText()
            _cmd = f'{chip_path}chip-tool administratorcommissioning read {_att_name} {_dst} 0'
            if _att_name == '0xFFFFFFFF':
                _cmd = f'{chip_path}chip-tool administratorcommissioning read-by-id 0xFFFFFFFF {_dst} 0'
        # > identify cluster
        case 'identify_read':
            _att_name = ui.attrib_id_identify.currentText()
            _cmd = f'{chip_path}chip-tool identify read {_att_name} {_dst} 1'
            if _att_name == '0xFFFFFFFF':
                _cmd = f'{chip_path}chip-tool identify read-by-id 0xFFFFFFFF {_dst} 1'
        case 'identify':
            _id_time = ui.identify_time.text()
            if not _id_time.isdecimal():
                disp.put((ui.keynote, 'QTextBrowser.append', 'Identify time not valid'))
                return
            _cmd = f'{chip_path}chip-tool identify identify {_id_time} {_dst} 1'
        case 'identify_query':
            _cmd = f'{chip_path}chip-tool identify identify-query {_dst} 1'
        case 'identify_trigger_effect':
            _ef_id, _ef_var = ui.effect_id.currentText(), ui.effect_variant.currentText()
            if not _ef_id.isdecimal():
                disp.put((ui.keynote, 'QTextBrowser.append', 'Identify effect_id not valid'))
                return
            _cmd = f'{chip_path}chip-tool identify trigger-effect {_ef_id} {_ef_var} {_dst} 1'
        # > Commissioning Cluster
        case 'ocw_bcm':
            _ocw_t, _interac_t = ui.timeout_bcm.text(), ui.interactionTimeout_bcm.text()
            if not _ocw_t.isdecimal():
                _ocw_t = '500'
            if not _interac_t.isdecimal():
                _cmd = (f'{chip_path}chip-tool administratorcommissioning open-basic-commissioning-window '
                        f'{_ocw_t} {_dst} 0')
            else:
                _cmd = (f'{chip_path}chip-tool administratorcommissioning open-basic-commissioning-window '
                        f'{_ocw_t} {_dst} 0 --timedInteractionTimeoutMs {_interac_t}')
        case 'ocw_revoke':
            _interac_t = ui.interactionTimeout_bcm.text()
            _cmd = (f'{chip_path}chip-tool administratorcommissioning revoke-commissioning {_dst} 0 '
                    f'--timedInteractionTimeoutMs {_interac_t}')
            if not _interac_t.isdecimal():
                _cmd = (f'{chip_path}chip-tool administratorcommissioning revoke-commissioning {_dst} 0 '
                        f'--timedInteractionTimeoutMs 1000')
        case 'bcm_dut_info_search':
            _cmd = (f'{chip_path}chip-all-clusters-app --discriminator {_dst}')
        case 'remove_fabric':
            _fabric_id = ui.fabric_ids.currentText()
            if not _fabric_id.isdecimal():
                disp.put((ui.keynote, 'QTextBrowser.append', 'Fabric ID invalid'))
                return
            _cmd = f'{chip_path}chip-tool operationalcredentials remove-fabric {_fabric_id} {_dst} 0'
        case 'open_window':  # ECM
            _opt, _timeout = ui.fabric_option.currentText()[0], ui.window_timeout.text()
            _discr = ui.fabric_discriminator.text()
            if not _timeout.isdecimal() or _timeout == '0':
                _timeout = '900'
                disp.put((ui.window_timeout, 'QLineEdit.setText', f'{_timeout}'))
            if not _discr.isdecimal():
                _discr = '4094'
                disp.put((ui.fabric_discriminator, 'QLineEdit.setText', '4094'))
            if int(_discr) > 4095:
                disp.put((ui.keynote, 'QTextBrowser.append',
                          'Invalid argument discriminator, it should between 0 ~ 4095'))
                return
            _cmd = f'{chip_path}chip-tool pairing open-commissioning-window {_dst} {_opt} {_timeout}  2000 {_discr}'
        case 'avahi_browse_udp':
            _cmd = 'avahi-browse -rt _matterc._udp'
        case 'avahi_browse_tcp':
            _cmd = 'avahi-browse -rt _matter._tcp'
        case 'read_fabrics':
            _cmd = f'{chip_path}chip-tool operationalcredentials read fabrics {_dst} 0 --fabric-filtered 0'
        case 'window_status':
            _cmd = f'{chip_path}chip-tool administratorcommissioning read window-status {_dst} 0'
        case 'open_window_with_name':
            _name = ui.commissioner_name.currentText()
            # TODO
        # > ota
        case 'ota_read':
            _att_name = ui.attrib_id_ota.currentText()
            _cmd = f'{chip_path}chip-tool otasoftwareupdaterequestor read {_att_name} {_dst} 0'
            if _att_name == '0xFFFFFFFF':
                _cmd = f'{chip_path}chip-tool otasoftwareupdaterequestor read-by-id 0xFFFFFFFF {_dst} 0'
        case 'ota_write':
            _att_name, _val = ui.attrib_id_ota.currentText(), ui.attrib_value_ota.currentText()
            if _val == '':
                disp.put((ui.keynote, 'QTextBrowser.append',
                          'the value of attribute you want to modify is invalid'))
                return
            _cmd = f'{chip_path}chip-tool otasoftwareupdaterequestor write {_att_name} {_val} {_dst} 0'
        case 'pairing_pi':
            _cmd = f'{chip_path}chip-tool pairing onnetwork 110 20202021'
        case 'ota_write_acl':
            _cmd = """
                        %schip-tool accesscontrol write acl '[{"fabricIndex": 1, "privilege": 5, "authMode": 2, 
                        "subjects": [112233], "targets": null}, {"fabricIndex": 1, "privilege": 5, "authMode": 2, 
                        "subjects": null, "targets": [{"cluster": 41, "endpoint": null, "deviceType": null}]}]' 110 0
                        """ % chip_path
        case 'announce_ota_file':
            _cmd = f'{chip_path}chip-tool otasoftwareupdaterequestor announce-otaprovider 110 0 0 0 {_dst} 0'
        # > Diga
        case 'read_sw_diagnostics':
            _att_name = ui.attrib_id_sw_diagnostics.currentText()
            _cmd = f'{chip_path}chip-tool softwarediagnostics read {_att_name} {_dst} 0'
            if _att_name == '0xFFFFFFFF':
                _cmd = f'{chip_path}chip-tool softwarediagnostics read-by-id 0xFFFFFFFF {_dst} 0'
        case 'read_general_diagnostics':
            _att_name = ui.attrib_id_general_diagnostics.currentText()
            _cmd = f'{chip_path}chip-tool generaldiagnostics read {_att_name} {_dst} 0'
            if _att_name == '0xFFFFFFFF':
                _cmd = f'{chip_path}chip-tool generaldiagnostics read-by-id 0xFFFFFFFF {_dst} 0'
        case 'read_wifinetworkdiagnostics':
            _att_name = ui.attrib_id_wifinetworkdiagnostics.currentText()
            _cmd = f'{chip_path}chip-tool wifinetworkdiagnostics read {_att_name} {_dst} 0'
            if _att_name == '0xFFFFFFFF':
                _cmd = f'{chip_path}chip-tool wifinetworkdiagnostics read-by-id 0xFFFFFFFF {_dst} 0'
        case 'read_user_label':
            _att_name = ui.attrib_user_label.currentText()
            _cmd = f'{chip_path}chip-tool userlabel read {_att_name} {_dst} 0'
            if _att_name == '0xFFFFFFFF':
                _cmd = f'{chip_path}chip-tool userlabel read-by-id 0xFFFFFFFF {_dst} 0'
        case 'read_fixed_label':
            _att_name = ui.attrib_id_fixed_label.currentText()
            _cmd = f'{chip_path}chip-tool fixedlabel read {_att_name} {_dst} 0'
            if _att_name == '0xFFFFFFFF':
                _cmd = f'{chip_path}chip-tool fixedlabel read-by-id 0xFFFFFFFF {_dst} 0'
        case 'read_lcfg':
            _att_name = ui.attrib_id_lcfg.currentText()
            _cmd = f'{chip_path}chip-tool localizationconfiguration read {_att_name} {_dst} 0'
            if _att_name == '0xFFFFFFFF':
                _cmd = f'{chip_path}chip-tool localizationconfiguration read-by-id 0xFFFFFFFF {_dst} 0'
        case 'read_ltime':
            _att_name = ui.attrib_id_ltime.currentText()
            _cmd = f'{chip_path}chip-tool timeformatlocalization read {_att_name} {_dst} 0'
            if _att_name == '0xFFFFFFFF':
                _cmd = f'{chip_path}chip-tool timeformatlocalization read-by-id 0xFFFFFFFF {_dst} 0'
        case 'read_timesync':
            _att_name = ui.attrib_id_timesync.currentText()
            _cmd = f'{chip_path}chip-tool timesynchronization read {_att_name} {_dst} 0'
            if _att_name == '0xFFFFFFFF':
                _cmd = f'{chip_path}chip-tool timesynchronization read-by-id 0xFFFFFFFF {_dst} 0'
        case 'read_grpkey':
            _att_name = ui.attrib_id_grpkey.currentText()
            _cmd = f'{chip_path}chip-tool groupkeymanagement read {_att_name} {_dst} 0'
            if _att_name == '0xFFFFFFFF':
                _cmd = f'{chip_path}chip-tool groupkeymanagement read-by-id 0xFFFFFFFF {_dst} 0'
        case 'key_set_write':
            group_key_set_id, security_policy = ui.group_key_set_id.currentText(), ui.group_key_sec_policy.currentText()
            epoch_key_0, epoch_key_1 = ui.epoch_key_0.currentText(), ui.epoch_key_1.currentText()
            epoch_key_2 = ui.epoch_key_2.currentText()
            epoch_start_time_0 = ui.epoch_start_time_0.currentText()
            epoch_start_time_1 = ui.epoch_start_time_1.currentText()
            epoch_start_time_2 = ui.epoch_start_time_2.currentText()
            cmd_prefix = f'{chip_path}chip-tool ' + "groupkeymanagement key-set-write '{"
            cmd_tail = "}' " + f'{_dst} 0'
            cmd_payload = f'"groupKeySetID": {group_key_set_id},"groupKeySecurityPolicy": {security_policy}, ' \
                          f'"epochKey0":"{epoch_key_0}", "epochStartTime0": {epoch_start_time_0},' \
                          f'"epochKey1":"{epoch_key_1}", "epochStartTime1": {epoch_start_time_1},' \
                          f'"epochKey2":"{epoch_key_2}", "epochStartTime2": {epoch_start_time_2}'
            _cmd = cmd_prefix + cmd_payload + cmd_tail
            disp.put((ui.keynote, 'QTextBrowser.append',
                                  f'groupKeyManagement key-set-write:\n\tgroupKeySetID-->'
                                  f'{group_key_set_id}\n\tsecurity_policy-->{security_policy}'))
        case 'write_group_key_map':
            groupId, groupKeySetID, fabricIndex = ui.group_id.currentText(), ui.group_key_set_id.currentText(), \
                ui.fabric_index.currentText()
            cmd_prefix = f'{chip_path}chip-tool ' + "groupkeymanagement write group-key-map '[{"
            cmd_tail = "}]' " + f'{_dst} 0'
            cmd_payload = f'"groupId": {groupId}, "groupKeySetID": {groupKeySetID}, "fabricIndex": {fabricIndex}'
            _cmd = cmd_prefix + cmd_payload + cmd_tail
        case 'add_group':
            _group_id, _group_name = ui.group_id.currentText(), ui.group_name.currentText()
            _cmd = f'{chip_path}chip-tool groups add-group {_group_id} {_group_name} {_dst} 1'
        case 'read_group_table':
            _cmd = f'{chip_path}chip-tool groupkeymanagement read group-table {_dst} 0'
        case 'view_group':
            _group_id = ui.group_id.currentText()
            _cmd = f'{chip_path}chip-tool groups view-group {_group_id} {_dst} 1'
        case 'remove_group':
            _group_id = ui.group_id.currentText()
            _cmd = f'{chip_path}chip-tool groups remove-group {_group_id} {_dst} 1'
        case 'remove_all_groups':
            _cmd = f'{chip_path}chip-tool groups remove-all-groups {_dst} 1'
        case 'get_group_membership':
            _groups_list = ui.gp_membership_list.currentText()
            if _groups_list[0] != '[' or _groups_list[-1] != ']':
                disp.put((ui.keynote, 'QTextBrowser.append', 'groups-list of get-group-membership command is invalid'))
                return
            _cmd = f'{chip_path}chip-tool groups get-group-membership {_groups_list} {_dst} 1'
        case 'add_group_if_identifying':
            group_id, group_name = ui.group_id.currentText(), ui.group_name.currentText()
            _cmd = f'{chip_path}chip-tool groups add-group-if-identifying {group_id} {group_name} {_dst} 1'
        # > DM
        case 'scan_networks':
            _ssid = ui.nc_ssid.currentText()
            _ssid_hex = ''
            if _ssid == '':
                _cmd = f'{chip_path}chip-tool networkcommissioning scan-networks {_dst} 0 --Ssid null --Breadcrumb 1'
            elif _ssid.isascii():
                # for ASCII symbol SSID
                _ssid_hex = ''.join([hex(ord(c))[2:].zfill(2).upper() for c in _ssid])
                _cmd = (f'{chip_path}chip-tool networkcommissioning scan-networks {_dst} 0 --Ssid hex:{_ssid_hex} '
                        f'--Breadcrumb 2')
            elif not _ssid.isascii():
                # for None-ASCII SSID
                _ssid_bytes = _ssid.encode('utf-8')
                _ssid_hex = _ssid_bytes.hex().upper()
                _cmd = f'{chip_path}chip-tool ' + f'networkcommissioning scan-networks {_dst} 0 ' \
                                                  f'--Ssid hex:{_ssid_hex} --Breadcrumb 2'
            else:
                disp.put((ui.keynote, 'QTextBrowser.append', 'target ssid invalid'))
                return
        case 'arm_fail_safe':
            if ui.arm_fail_safe.text() == 'armed fail-safe on':
                _cmd = f'{chip_path}chip-tool generalcommissioning arm-fail-safe 900 1 {_dst} 0'
                disp.put((ui.arm_fail_safe, 'QButton.setText', 'armed fail-safe off'))
            else:
                _cmd = f'{chip_path}chip-tool generalcommissioning arm-fail-safe 0 0 {_dst} 0'
                disp.put((ui.arm_fail_safe, 'QButton.setText', 'armed fail-safe on'))
        case 'add_update_wifi_nwk':
            ssid, psk, ssid_hex = ui.ssid_nc.text(), ui.psk_nc.text(), ''
            if ssid.isascii():
                # for ASCII symbol SSID
                ssid_hex = ''.join([hex(ord(c))[2:].zfill(2).upper() for c in ssid])
            elif not ssid.isascii():
                # for None-ASCII SSID
                ssid_bytes = ssid.encode('utf-8')
                ssid_hex = ssid_bytes.hex().upper()
            else:
                disp.put((ui.keynote, 'QTextBrowser.append', 'SSID invalid'))
                return
            _cmd = (f'{chip_path}chip-tool networkcommissioning add-or-update-wi-fi-network '
                    f'hex:{ssid_hex} {psk} {_dst} 0')
        case 'remove_network':
            ssid, ssid_hex = ui.ssid_nc.text(), ''
            if ssid.isascii():
                # for ASCII symbol SSID
                ssid_hex = ''.join([hex(ord(c))[2:].zfill(2).upper() for c in ssid])
            elif not ssid.isascii():
                # for None-ASCII SSID
                ssid_bytes = ssid.encode('utf-8')
                ssid_hex = ssid_bytes.hex().upper()
            else:
                disp.put((ui.keynote, 'QTextBrowser.append', 'SSID invalid'))
                return
            _cmd = f'{chip_path}chip-tool networkcommissioning remove-network  hex:{ssid_hex} {_dst} 0'
        case 'connect_network':
            ssid, ssid_hex = ui.ssid_nc.text(), ''
            if ssid.isascii():
                # for ASCII symbol SSID
                ssid_hex = ''.join([hex(ord(c))[2:].zfill(2).upper() for c in ssid])
            elif not ssid.isascii():
                # for None-ASCII SSID
                ssid_bytes = ssid.encode('utf-8')
                ssid_hex = ssid_bytes.hex().upper()
            else:
                disp.put((ui.keynote, 'QTextBrowser.append', 'SSID invalid'))
                return
            _cmd = f'{chip_path}chip-tool networkcommissioning connect-network  hex:{ssid_hex} {_dst} 0'
        case 'csrrequest':
            _cmd = f'{chip_path}chip-tool operationalcredentials csrrequest ' \
                   f'hex:C11D6EAA00A54066220DA7F3FC5DC0F684C13D8B8FD3758B51163C2AEDD6F10F {_dst} 0 ' \
                   f'--IsForUpdateNOC 0 --trace_decode 1'
        case 'attestation_request':
            _cmd = f'{chip_path}chip-tool operationalcredentials attestation-request ' \
                   f'hex:3577CA6EFFFC560E287604663AE5BE2F11D1B1CF99BE326AF5B3B114A2E91395 {_dst} 0 --trace_decode 1'
        case 'cert_chain_dac_request':
            _cmd = f'{chip_path}chip-tool operationalcredentials certificate-chain-request 1 {_dst} 0 --trace_decode 1'
        case 'cert_chain_pai_request':
            _cmd = f'{chip_path}chip-tool operationalcredentials certificate-chain-request 2 {_dst} 0 --trace_decode 1'
        # > OnOff Cluster
        case 'off':
            ui.onoff.setText('on')
            _cmd = f'{chip_path}chip-tool onoff on {_dst} 1'
            ui.onoff.setIcon(qta.icon('mdi.lightbulb-on', color='gold'))
            ui.toggle.setIcon(qta.icon('mdi.lightbulb-on', color='gold'))
        case 'on':
            ui.onoff.setText('off')
            _cmd = f'{chip_path}chip-tool onoff off {_dst} 1'
            ui.onoff.setIcon(qta.icon('mdi6.lightbulb-off'))
            ui.toggle.setIcon(qta.icon('mdi6.lightbulb-off'))
        case 'toggle':
            _onoff = ui.onoff.text()
            if _onoff == 'off':
                ui.onoff.setText('on')
                ui.onoff.setIcon(qta.icon('mdi.lightbulb-on', color='gold'))
                ui.toggle.setIcon(qta.icon('mdi.lightbulb-on', color='gold'))
            else:
                ui.onoff.setText('on')
                ui.onoff.setIcon(qta.icon('mdi.lightbulb-off'))
                ui.toggle.setIcon(qta.icon('mdi.lightbulb-off'))
            _cmd = f'{chip_path}chip-tool onoff toggle {_dst} 1'
        case 'read_onoff':
            _att_name = ui.attrib_id_onoff.currentText()
            _cmd = f'{chip_path}chip-tool onoff read {_att_name} {_dst} 1'
            if _att_name == '0xFFFFFFFF':  # wildcards
                _cmd = f'{chip_path}chip-tool onoff read-by-id 0xFFFFFFFF {_dst} 1'
        case 'on_with_timed_off':
            _on_off_control = '0'
            _on_time, _off_wait_time = ui.off_effect_id.currentText(), ui.off_effect_variant.currentText()
            if (not _on_time.isdecimal()) or (not _off_wait_time.isdecimal()):
                _on_time, _off_wait_time = '60', '100'
                disp.put((ui.keynote, 'QTextBrowser.append',
                          'on_time, off-wait-time set to default value 60 & 100 （1/10 s）'))
            _cmd = f'{chip_path}chip-tool onoff on-with-timed-off {_on_off_control} {_on_time} {_off_wait_time} {_dst} 1'
        case 'off_with_effect':
            _ef_id, _var = ui.off_effect_id.currentText(), ui.off_effect_variant.currentText()
            if (not _ef_id.isdecimal()) or (not _var.isdecimal()):
                _ef_id, _var = '0', '0'
            if _ef_id == '1':
                # effect_id 0x01: Dying Light
                # # 20% dim up in 0.5s then fade to off in 1 second
                _var = '0'
            if _ef_id == '0':
                # effect_id 0x00: Delayed All Off
                # # 0: Fade to off in 0.8 seconds
                # # 1: No fade
                # # 2: 50% dim down in 0.8 seconds then fade to off in 12 seconds
                if _var not in ['0', '1', '2']:
                    _var = '0'
                    disp.put((ui.keynote, 'QTextBrowser.append',
                              'off-with-effect variant field invalid, set it to default 0x00'))
            _cmd = f'{chip_path}chip-tool onoff off-with-effect {_ef_id} {_var} {_dst} 1'
        case 'on_with_recall_global_scene':
            _cmd = f'{chip_path}chip-tool onoff on-with-recall-global-scene {_dst} 1'
        # > lvl cluster
        case 'move_to_level':
            level = ui.level.currentText()
            _cmd = f'{chip_path}chip-tool levelcontrol move-to-level {level} {_tra} {_opt} {_ovr} {_dst} 1'
        case 'move_to_level_with_on_off':
            level = ui.level.currentText()
            _cmd = f'{chip_path}chip-tool levelcontrol move-to-level-with-on-off {level} {_tra} {_opt} {_ovr} {_dst} 1'
        case 'move_to_level_with_on_off':
            level = ui.level.currentText()
            _cmd = f'{chip_path}chip-tool levelcontrol move-to-level-with-on-off {level} {_tra} {_opt} {_ovr} {_dst} 1'
        case 'read_level':
            _att_name = ui.attrib_id_level.currentText()
            _cmd = f'{chip_path}chip-tool levelcontrol read {_att_name} {_dst} 1'
            if _att_name == '0xFFFFFFFF':  # wildcards
                _cmd = f'{chip_path}chip-tool levelcontrol read-by-id 0xFFFFFFFF {_dst} 1'
        case 'move_up':
            move_rate = ui.move_rate.currentText()
            _cmd = f'{chip_path}chip-tool levelcontrol move 0 {move_rate} {_opt} {_ovr} {_dst} 1'
        case 'move_down':
            move_rate = ui.move_rate.currentText()
            _cmd = f'{chip_path}chip-tool levelcontrol move 1 {move_rate} {_opt} {_ovr} {_dst} 1'
        case 'move_with_on_off_up':
            move_rate = ui.move_rate.currentText()
            _cmd = f'{chip_path}chip-tool levelcontrol move-with-on-off 0 {move_rate} {_opt} {_ovr} {_dst} 1'
        case 'move_with_on_off_down':
            move_rate = ui.move_rate.currentText()
            _cmd = f'{chip_path}chip-tool levelcontrol move-with-on-off 1 {move_rate} {_opt} {_ovr} {_dst} 1'
        case 'step_up':
            step_size = ui.step_size.currentText()
            _cmd = f'{chip_path}chip-tool levelcontrol step 0 {step_size} {_tra} {_opt} {_ovr} {_dst} 1'
        case 'step_down':
            step_size = ui.step_size.currentText()
            _cmd = f'{chip_path}chip-tool levelcontrol step 1 {step_size} {_tra} {_opt} {_ovr} {_dst} 1'
        case 'step_up_with_on_off':
            step_size = ui.step_size.currentText()
            _cmd = f'{chip_path}chip-tool levelcontrol step-with-on-off 0 {step_size} {_tra} {_opt} {_ovr} {_dst} 1'
        case 'step_down_with_on_off':
            step_size = ui.step_size.currentText()
            _cmd = f'{chip_path}chip-tool levelcontrol step-with-on-off 1 {step_size} {_tra} {_opt} {_ovr} {_dst} 1'
        case 'stop':
            _cmd = f'{chip_path}chip-tool levelcontrol stop {_opt} {_ovr} {_dst} 1'
        case 'stop_with_on_off':
            _cmd = f'{chip_path}chip-tool levelcontrol stop-with-on-off {_opt} {_ovr} {_dst} 1'
        # > Color Control Cluster
        case 'move_to_color_temperature':
            cct = str(1000000 // int(ui.color_temp.currentText()))
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-color-temperature {cct} {_tra} {_opt} {_ovr} {_dst} 1'
        case 'read_cc':
            _att_name = ui.attrib_id_cc.currentText()
            _cmd = f'{chip_path}chip-tool colorcontrol read {_att_name} {_dst} 1'
            if _att_name == '0xFFFFFFFF':  # wildcards
                _cmd = f'{chip_path}chip-tool colorcontrol read-by-id {_att_name} {_dst} 1'
        case 'move_to_hue':
            # Matter spec ， Hue range is [0, 254]
            hue, direction = ui.hue_move_to.currentText(), ui.mv_to_hue_direction.currentText()[0]
            if not hue.isdecimal() or int(hue) > 254:
                disp.put((ui.keynote, 'QTextBrowser.append', 'Hue value out of range, it should be 0~254.'))
                return
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue {hue} {direction} {_tra} {_opt} {_ovr} {_dst} 1'
        case 'move_hue':
            mode, rate = ui.move_hue_mode.currentText()[0], ui.rate_mv_hue.currentText()
            if not rate.isdecimal():
                disp.put((ui.keynote, 'QTextBrowser.append', 'Hue value out of range, it should be 0~254.'))
                return
            _cmd = f'{chip_path}chip-tool colorcontrol move-hue {mode} {rate} {_opt} {_ovr} {_dst} 1'
        case 'step_hue':
            mode, step_size = ui.step_hue_mode.currentText()[0], ui.step_hue_size.currentText()
            if not mode.isdecimal() or not step_size.isdecimal():
                disp.put((ui.keynote, 'QTextBrowser.append', 'Hue step_size value out of range, it should be 0~254.'))
                return
            _cmd = f'{chip_path}chip-tool colorcontrol step-hue {mode} {step_size} {_tra} {_opt} {_ovr} {_dst} 1'
        case 'move_to_saturation':
            saturation = ui.sta_move_to.currentText()
            if not saturation.isdecimal():
                disp.put((ui.keynote, 'QTextBrowser.append', 'Saturation value out of range, it should be 0~254.'))
                return
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-saturation {saturation} {_tra} {_opt} {_ovr} {_dst} 1'
        case 'move_saturation':
            mode, rate = ui.move_sat_mode.currentText()[0], ui.move_sat_rate.currentText()
            if not rate.isdecimal() or not mode.isdecimal():
                disp.put((ui.keynote, 'QTextBrowser.append', 'Hue/Saturation value out of range, it should be 0~254'))
                return
            _cmd = f'{chip_path}chip-tool colorcontrol move-saturation {mode} {rate} {_opt} {_ovr} {_dst} 1'
        case 'step_saturation':
            mode, step_size = ui.step_sat_mode.currentText()[0], ui.step_sat_size.currentText()
            if not step_size.isdecimal() or not mode.isdecimal():
                disp.put((ui.keynote, 'QTextBrowser.append', 'Hue/Saturation value out of range, it should be 0~254'))
                return
            _cmd = f'{chip_path}chip-tool colorcontrol step-saturation {mode} {step_size} {_tra} {_opt} {_ovr} {_dst} 1'
        case 'move_to_hue_and_saturation':
            hue, sat = ui.hue.currentText(), ui.saturation.currentText()
            if not hue.isdecimal() or not sat.isdecimal():
                disp.put((ui.keynote, 'QTextBrowser.append', 'Hue/Saturation value out of range, it should be 0~254'))
                return
            _cmd = (f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} '
                    f'{_opt} {_ovr} {_dst} 1')
        case 'move_to_color':
            color_x, color_y = ui.current_x.currentText(), ui.current_y.currentText()
            if not color_x.isdecimal() or not color_y.isdecimal():
                disp.put((ui.keynote, 'QTextBrowser.append', 'Color X/Y not valid'))
                return
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-color {color_x} {color_y} {_tra} {_opt} {_ovr} {_dst} 1'
        case 'move_color':
            rate_x, rate_y = ui.rate_x.currentText(), ui.rate_y.currentText()
            if not rate_x.isdecimal() or not rate_y.isdecimal():
                disp.put((ui.keynote, 'QTextBrowser.append', 'rateX/rateY not valid'))
                return
            _cmd = f'{chip_path}chip-tool colorcontrol move-color {rate_x} {rate_y} {_opt} {_ovr} {_dst} 1'
        case 'step_color':
            stepX, stepY = ui.step_x.currentText(), ui.step_y.currentText()
            if not stepX.isdecimal() or not stepY.isdecimal():
                disp.put((ui.keynote, 'QTextBrowser.append', 'stepX/stepY not valid'))
                return
            _cmd = f'{chip_path}chip-tool colorcontrol step-color {stepX} {stepY} {_tra} {_opt} {_ovr} {_dst} 1'
        case 'stop_move_step':
            _cmd = f'{chip_path}chip-tool colorcontrol stop-move-step 255 255 {_dst} 1'
        case 'en_move_hue':
            _mv_mode, _mv_rate = ui.en_move_hue_mode.currentText()[0], ui.rate_mv_hue_en.currentText()
            if _mv_mode not in ['0', '1', '3']:
                disp.put((ui.keynote, 'QTextBrowser.append', 'MoveMode invalid, it should be 0/1/3'))
                _mv_mode = '0'
            _cmd = f'{chip_path}chip-tool colorcontrol enhanced-move-hue {_mv_mode} {_mv_rate} {_opt} {_ovr} {_dst} 1'
        case 'en_move_to_hue':
            _direction = ui.en_mv_to_hue_direction.currentText()[0]
            _en_hue = ui.en_hue_move_to.currentText()
            """
            if not _en_hue.isdecimal():
                disp.put((ui.keynote, 'QTextBrowser.append', 'EnhancedHue Invalid, it should be 0~254'))
                _en_hue = '0'
            """
            if _direction not in ['0', '1', '2', '3']:
                disp.put((ui.keynote, 'QTextBrowser.append',
                          'direction of enhanced-move-to-hue command invalid, it should be 0~3'))
                _direction = '0'
            _cmd = f'{chip_path}chip-tool colorcontrol enhanced-move-to-hue {_en_hue} {_direction} {_tra}' \
                   f' {_opt} {_ovr} {_dst} 1'
        case 'en_step_hue':
            _en_step_mode, _en_step_size = ui.en_step_hue_mode.currentText()[0], ui.en_step_hue_size.currentText()
            if _en_step_mode not in ['1', '3']:
                disp.put((ui.keynote, 'QTextBrowser.append', 'MoveMode invalid, it should be 1/3'))
                _en_step_mode = '1'
            _cmd = f'{chip_path}chip-tool colorcontrol enhanced-step-hue {_en_step_mode} {_en_step_size} ' \
                   f'{_tra} {_opt} {_ovr} {_dst} 1'
        case 'en_move_to_hue_sat':
            _en_hue, _en_sta = ui.en_hue.currentText(), ui.en_sat.currentText()
            _cmd = f'{chip_path}chip-tool colorcontrol enhanced-move-to-hue-and-saturation {_en_hue} {_en_sta}' \
                   f' {_tra} {_opt} {_ovr} {_dst} 1'
        case 'move_to_hue_red':
            hue, sat = 0, 254
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'move_to_hue_green':
            hue, sat = 84, 254
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'move_to_hue_blue':
            hue, sat = 169, 254
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'move_to_hue_yellow':
            hue, sat = 42, 254
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'move_to_hue_teal':
            hue, sat = 127, 254
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'move_to_hue_purple':
            hue, sat = 195, 221
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'move_to_hue_orange':
            hue, sat = 27, 254
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'move_to_hue_gold':
            hue, sat = 35, 254
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'move_to_hue_deeppink':
            hue, sat = 245, 235
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'move_to_hue_midnightblue':
            hue, sat = 170, 198
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'echo_red':
            hue, sat = 0, 254
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'echo_crimson':
            hue, sat = 245, 230
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'echo_salmon':
            hue, sat = 11, 132
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'echo_orange':
            hue, sat = 27, 254
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'echo_gold':
            hue, sat = 35, 254
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'echo_yellow':
            hue, sat = 42, 254
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'echo_green':
            hue, sat = 84, 254
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'echo_turquoise':
            hue, sat = 122, 182
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'echo_pink':
            hue, sat = 245, 63
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'echo_magenta':
            hue, sat = 211, 254
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'echo_cyan':
            hue, sat = 127, 254
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'echo_skyblue':
            hue, sat = 138, 107
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'echo_blue':
            hue, sat = 169, 254
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'echo_purple':
            hue, sat = 195, 218
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'echo_lavender':
            hue, sat = 179, 127
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'echo_white':
            hue, sat = 0, 0
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-hue-and-saturation {hue} {sat} {_tra} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'move_to_color_red':
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-color 48168 17367 1 255 255 {_dst} 1'
        case 'move_to_color_green':
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-color 7537 54133 1 255 255 {_dst} 1'
        case 'move_to_color_blue':
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-color 10290 1180 1 255 255 {_dst} 1'
        case 'move_to_color_yellow':
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-color 27678 35909 1 255 255 {_dst} 1'
        case 'move_to_color_purple':
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-color 17228 5061 1 255 255 {_dst} 1'
        case 'move_to_color_orange':
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-color 36921 27545 1 255 255 {_dst} 1'
        case 'move_to_color_deeppink':
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-color 36926 16834 1 255 255 {_dst} 1'
        case 'move_to_color_teal':
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-color 9140 23283 1 255 255 {_dst} 1'
        case 'move_to_color_midnightblue':
            _cmd = f'{chip_path}chip-tool colorcontrol move-to-color 11656 3908 1 255 255 {_dst} 1'
        case 'color_loop_set':
            _update_flags, _action, _direction, _cc_time, _start_hue = ui.update_flags.currentText(), \
                ui.action.currentText()[0], ui.cc_time.currentText(), ui.direction.currentText()[0], \
                ui.start_hue.currentText()
            if _update_flags not in ['0', '1', '2', '3', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15']:
                _update_flags = '0'
            if (not _cc_time.isdecimal() or not _action.isdecimal() or not _direction.isdecimal()
                    or not _start_hue.isdecimal()):
                _cc_time, _direction, _action, _start_hue = '10', '0', '0', '0'
            _cmd = (f'{chip_path}chip-tool colorcontrol color-loop-set {_update_flags} {_action} {_direction} '
                    f'{_cc_time} {_start_hue} {_opt} {_ovr} {_dst} 1')
        case 'move_color_temperature':
            _mode, _rate, _min, _max = ui.move_temp_mode.currentText()[0], ui.move_temp_rate.currentText(), \
                ui.min_temp.currentText(), ui.max_temp.currentText()
            if not (_mode.isdecimal() and _rate.isdecimal() and _min.isdecimal() and _max.isdecimal()):
                _mode, _rate, _min, _max = '0', '10', '153', '370'
            _cmd = f'{chip_path}chip-tool colorcontrol move-color-temperature {_mode} {_rate} {_min} {_max} ' \
                   f'{_opt} {_ovr} {_dst} 1'
        case 'step_color_temperature':
            _mode, _size, _step_min, _step_max = ui.move_temp_mode.currentText()[0], \
                ui.step_temp_size.currentText(), ui.min_temp.currentText(), ui.max_temp.currentText()
            if not (_mode.isdecimal() and _size.isdecimal() and _step_min.isdecimal() and _step_max.isdecimal()):
                _mode, _size, _step_min, _step_max = '0', '10', '153', '370'
            _cmd = f'{chip_path}chip-tool colorcontrol step-color-temperature {_mode} {_size} {_tra} ' \
                   f'{_step_min} {_step_max} {_opt} {_ovr} {_dst} 1'
        case '':
            pass
        case '':
            pass
        case '':
            pass
        case '':
            pass
        case '':
            pass
        case '':
            pass
        case '':
            pass
        case '':
            pass
        case '':
            pass
        case '':
            pass
        case '':
            pass
        case '':
            pass
        case _:
            disp.put((ui.keynote, 'QTextBrowser.append',
                      f'>>** Bellow command does not re-formatted, may not works correctly **<<'))
            _cmd = cmd

    # >> 3. cmd send out
    try:
        if _c_name:
            _cmd = _cmd + f' --commissioner-name {_c_name}'
        if ssh_ch.send_ready():
            disp.put((ui.keynote, 'QTextBrowser.append',
                      f'\n<< {_cmd.replace("/home/ubuntu/apps/chip-tool", "")} >>'))
            ssh_ch.send(_cmd + '\n')  # '/home/ubuntu/apps/' + _cmd + '\n'
    except Exception as E:
        disp.put((ui.keynote, 'QTextBrowser.append', str(E)))
        disp.put((ui.keynote, 'QTextBrowser.append', str(traceback.format_exc())))
